package com.lmaos.allcontrol.beancontrol.method_;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.lmaos.allcontrol.beancontrol.class_.ClassUtils;
/** 方法工具,通过反射操作方法,均为静态调用
 * 
 * @author lmaos 
 * 2016年11月14日 上午10:50:12
 */
public class MethodUtils {
	/** 方法缓存 初始时申请128长度,保证允许更多的线程同时访问
	 * 
	 */
	protected static Map<Class, Map<String,Method>> methodCache = new ConcurrentHashMap<Class, Map<String,Method>>(128);
	private static Object MethodCacheLock = new Object();
	
	/** 生成一个方法的key
	 * 
	 * @param method
	 * @return
	 */
	public static String getMethodKey(Method method){
		String key = getMethodKey(method.getName(), method.getParameterTypes());
		return key;
	}
	
	/** 生成一个方法的key
	 * 
	 * @param method
	 * @param params
	 * @return
	 */
	public static String getMethodKey(String method,Class... params){
		StringBuffer key_buf = new StringBuffer(method);
		if(params!=null&&params.length>0){
			for (Class param : params) {
				key_buf.append(param.hashCode()).append(",");	// 通过hashcode确定方法key。
//				key_buf.append(param.getName()).append(",");	// 通过方法名确定方法key。
			}
			key_buf.replace(key_buf.length()-1, key_buf.length(), "");
		}
		String key = key_buf.toString();
		return key;
	}
	/** 添加一个方法的缓存。。
	 * 
	 * @param clazz
	 * @param method
	 * @param replace 如果true 则如果存在这个key指向的方法则替换。如果false 则不替换
	 */
	public static void addMethodCache(Class clazz,Method method){
		
		Map<String,Method> subMethodCache = methodCache.get(clazz); // 获取这个子缓存
		if(subMethodCache == null){
			synchronized (MethodCacheLock) {						// 此处同步不会有第二个线程同时操作
				subMethodCache = methodCache.get(clazz);				
				if(subMethodCache == null){							 // 确定缓存不存在
					subMethodCache = new HashMap<String,Method>();
					methodCache.put(clazz, subMethodCache);
				}
			}
		}
		String key = getMethodKey(method);
		if(!subMethodCache.containsKey(key)){
			subMethodCache.put(key, method);
		}
	}
	
	/** 从缓存获取当前方法
	 * 
	 * @param clazz
	 * @param name
	 * @param params 携带参数类型
	 * @return
	 */
	protected static Method getMethodByCache(Class clazz, String name, Class... params){
		Map<String,Method> subMethodCache = methodCache.get(clazz); // 获取这个子缓存
		Method method = null;
		if(subMethodCache!=null){
			method = subMethodCache.get(getMethodKey(name, params));
		}
		return method;
	}
	
	protected static List<Method> getMethodsByCache(Class clazz){
		Map<String,Method> subMethodCache = methodCache.get(clazz); // 获取这个子缓存
		List<Method> methods = new ArrayList<Method>();
		if(subMethodCache!=null){
			methods.addAll(subMethodCache.values());
		}
		return methods;
	}
	
	
	
	// 加载方法到同步锁,多线程时候线程安全
	protected final static Object loadMethodsLock = new Object();
	/** 加载全部都方法到缓存中。
	 * 
	 * @param clazz
	 */
	public static void loadAllMethods(Class clazz,boolean replace){
		synchronized (loadMethodsLock) {
			
			/* *********************************************************** *
			 * 如果不存在当前缓存，则首先查询当前类所有继承的类。
			 * 得到所有继承的类后装载所有放假,会从子类一直加载到继承的父类上。
			 * *********************************************************** */
			if(!methodCache.containsKey(clazz)){
				Map<String,Method> subMethodCache = new HashMap<String, Method>();
				List<Class> classs = ClassUtils.getClassAll(clazz, false);
				for (Class cl : classs) {
					Method[] methods = cl.getDeclaredMethods();
					for (Method method : methods) {
						method.setAccessible(true); // 设置访问权限,设置为true 则可以对这个方法非法修改与访问
						String key = getMethodKey(method);
						if(!subMethodCache.containsKey(key)){
							subMethodCache.put(key, method);
						}
//						addMethodCache(clazz, method);
					}
				} // for-end
				methodCache.put(clazz, subMethodCache);
			}else if(replace){ // 替换操作
				
				Map<String,Method> subMethodCache = new HashMap<String,Method>();
				
				List<Class> classs = ClassUtils.getClassAll(clazz, true);
				for (Class cl : classs) {
					Method[] methods = cl.getDeclaredMethods();
					for (Method method : methods) {
						String key = method.getName();
						method.setAccessible(true); // 设置访问权限,设置为true 则可以对这个字段非法修改与访问
						subMethodCache.put(key, method);
					}
				} // for-end
				methodCache.put(clazz, subMethodCache);	//替换方法缓存
			}
		}
	}
	
	/** 加载全部都方法到缓存中。
	 * 
	 * @param clazz
	 */
	public static void loadAllMethods(Class clazz){
		loadAllMethods(clazz, false);
	}


	
	
	
	
	
	
	/** 获取方法
	 * 
	 * @param clazz
	 * @param name
	 * @return
	 */
	public static Method getMethod(Class clazz,String name, Class... params){
		
		if(!methodCache.containsKey(clazz)){
			loadAllMethods(clazz);
		}
		
		Method method = getMethodByCache(clazz, name, params);
		return method;
	}
	
	/** 获取当前对象中这个方法当对象
	 * 
	 * @param obj
	 * @param name
	 * @return
	 */
	public static Method getMethod(Object obj,String name, Class... params){
		Class clazz = obj.getClass();
		Method method = getMethod(clazz, name, params);
		return method;
	}
	
	public static List<Method> getMethods(Object obj){
		return getMethods(obj.getClass());
	}
	/** 获取全部都方法
	 * 
	 * @param clazz
	 * @return
	 */
	public static List<Method> getMethods(Class clazz){
		if(!methodCache.containsKey(clazz)){
			loadAllMethods(clazz);
		}
		return getMethodsByCache(clazz);
	}
	public static Map<String, Method> getMethodsToMap(Object obj){
		return getMethodsToMap(obj.getClass());
	}
	
	/** 获取这些方法集合，map结构
	 * 
	 * @param clazz
	 * @return
	 */
	public static Map<String, Method> getMethodsToMap(Class clazz){
		if(!methodCache.containsKey(clazz)){
			loadAllMethods(clazz);
		}
		Map<String,Method> subMethodCache = methodCache.get(clazz); // 获取这个子缓存
		if(subMethodCache==null){
			return new HashMap<String,Method>();
		}
		return new HashMap<String,Method>(subMethodCache);
	}
	/** 执行这个方法
	 * 
	 * @param obj
	 * @param name			方法名称
	 * @param clparam		方法中参数类型集合
	 * @param valparams		参数类型对应的传餐
	 * @return
	 * @throws Exception
	 */
	public static Object executeMethod(Object obj, String name,Class[] clparam,Object[] valparams) throws Exception{
		Method method = getMethod(obj, name, clparam);
		return executeMethod(obj, method, valparams);
	}
	
	/**
	 * 
	 * @param obj
	 * @param method		要执行的方法
	 * @param valparams		方法中参数
	 * @return
	 * @throws Exception
	 */
	public static Object executeMethod(Object obj, Method method,Object... valparams) throws Exception{
		if(method == null){
			System.err.println("传入方法为null");
			return null;
		}
		if(!method.isAccessible()){
			method.setAccessible(true);
		}
		return method.invoke(obj, valparams);
	}
	/** 查询被这些注解修饰到方法
	 * 
	 * @param clazz
	 * @param annotationClasss
	 * @return
	 */
	public static List<Method> indexMethodByAnnotation(Class clazz,Class... annotationClasss){
		if(annotationClasss == null || annotationClasss .length == 0){
			return getMethods(clazz);
		}
		/* ****************************************************** *
		 * 结果集合储存查询的被这些注解修饰当方法。
		 * 先查询出所有方法，然后一条一条匹配注解。
		 * ***************************************************** */
		List<Method> resultMethods = new ArrayList<Method>();
		List<Method> cacheMethods = getMethods(clazz);
		for (Method method : cacheMethods) {
			for (Class annotationClass : annotationClasss) {
				if(method.isAnnotationPresent(annotationClass)){
					resultMethods.add(method);
					break;
				}
			}
			
		}
		return resultMethods;
	}
	
	
	/** 查询方法名称为指定名称结束的
	 * 
	 * @param clazz
	 * @param end
	 * @return
	 */
	public static List<Method> indexMethodByEndText(Class clazz,String end){
		if(end == null || end.isEmpty()){
			return getMethods(clazz);
		}
		/* ****************************************************** *
		 * 结果集合储存查询的方法名为end结束。
		 * ***************************************************** */
		List<Method> cacheMethods = getMethods(clazz);
		List<Method> resultMethods = new ArrayList<Method>();	// 结果
		for (Method Method : cacheMethods) {
			if(Method.getName().endsWith(end)){
				resultMethods.add(Method);
			}
			
		}
		return resultMethods;
	}
	
	/** 查询方法名称包含指定的内容的所有方法
	 * 
	 * @param clazz
	 * @param include 包含的内容
	 * @return
	 */
	public static List<Method> indexMethodByIncludeText(Class clazz,String include){
		if(include == null || include.isEmpty()){
			return getMethods(clazz);
		}
		/* ****************************************************** *
		 * 结果集合储存查询的方法名包含include
		 * ***************************************************** */
		List<Method> cacheMethods = getMethods(clazz);
		List<Method> resultMethods = new ArrayList<Method>();	// 结果
		for (Method Method : cacheMethods) {
			if(Method.getName().indexOf(include)!=-1){
				resultMethods.add(Method);
			}
			
		}
		return resultMethods;
	}
	

}
